﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace YArchitech.Plumbing
{
	public class Matrix
	{
		public int RowCont
		{
			get
			{
				return this.rowCount;
			}
		}

		public int ColumnCount
		{
			get
			{
				return this.columnCount;
			}
		}

		public Matrix()
		{
			this.rowCount = 0;
			this.columnCount = 0;
		}

		public Matrix(int m, int n)
		{
			this.rowCount = m;
			this.columnCount = n;
			this.Values = new double[this.rowCount, this.columnCount];
		}

		public Matrix(int n)
		{
			this.rowCount = n;
			this.columnCount = n;
			this.Values = new double[this.rowCount, this.columnCount];
		}

		public Matrix(Matrix mat)
		{
			this.rowCount = mat.rowCount;
			this.columnCount = mat.columnCount;
			this.Values = new double[this.rowCount, this.columnCount];
			for (int i = 0; i < this.rowCount; i++)
			{
				for (int j = 0; j < this.columnCount; j++)
				{
					this.Values[i, j] = mat[i, j];
				}
			}
		}

		public double this[int i, int j]
		{
			get
			{
				return this.Values[i, j];
			}
			set
			{
				this.Values[i, j] = value;
			}
		}

		public override string ToString()
		{
			string text = "";
			for (int i = 0; i < this.rowCount; i++)
			{
				for (int j = 0; j < this.columnCount; j++)
				{
					text += string.Format("{0}\t", this[i, j].ToString("0.0000"));
				}
			}
			return text;
		}

		public void ZeroMatrix()
		{
			for (int i = 0; i < this.rowCount; i++)
			{
				for (int j = 0; j < this.columnCount; j++)
				{
					this[i, j] = 0.0;
				}
			}
		}

		public bool IsSameDimension(Matrix mat)
		{
			return mat.rowCount == this.rowCount && mat.columnCount == this.columnCount;
		}

		public static Matrix operator +(Matrix mat1, Matrix mat2)
		{
			Matrix matrix;
			if (mat1.IsSameDimension(mat2))
			{
				matrix = new Matrix(mat1.rowCount, mat1.columnCount);
				for (int i = 0; i < mat1.rowCount; i++)
				{
					for (int j = 0; j < mat1.columnCount; j++)
					{
						matrix[i, j] = mat1[i, j] + mat2[i, j];
					}
				}
			}
			else
			{
				matrix = new Matrix();
				MessageBox.Show("The two matrix have the different dimension!", "盈建科提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
			}
			return matrix;
		}

		public static Matrix operator -(Matrix mat1, Matrix mat2)
		{
			Matrix matrix;
			if (mat1.IsSameDimension(mat2))
			{
				matrix = new Matrix(mat1.rowCount, mat1.columnCount);
				for (int i = 0; i < mat1.rowCount; i++)
				{
					for (int j = 0; j < mat1.columnCount; j++)
					{
						matrix[i, j] = mat1[i, j] + mat2[i, j];
					}
				}
			}
			else
			{
				matrix = new Matrix();
				MessageBox.Show("The two matrix have the different dimension!", "盈建科提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
			}
			return matrix;
		}

		public static Matrix operator *(double number, Matrix mat)
		{
			Matrix matrix = new Matrix(mat.rowCount, mat.columnCount);
			for (int i = 0; i < mat.rowCount; i++)
			{
				for (int j = 0; j < mat.columnCount; j++)
				{
					matrix[i, j] = mat[i, j] * number;
				}
			}
			return matrix;
		}

		public static Matrix operator *(Matrix mat, double number)
		{
			return number * mat;
		}

		public static Matrix operator /(double number, Matrix mat)
		{
			return 1.0 / number * mat;
		}

		public static Matrix operator /(Matrix mat, double number)
		{
			return 1.0 / number * mat;
		}

		public static double RowMultiColumn(Matrix mat1, int rowNumber, Matrix mat2, int colNumber)
		{
			double num = 0.0;
			if (mat1.columnCount == mat2.rowCount)
			{
				for (int i = 0; i < mat2.rowCount; i++)
				{
					num += mat1[rowNumber, i] * mat2[i, colNumber];
				}
			}
			return num;
		}

		public static Matrix operator *(Matrix mat1, Matrix mat2)
		{
			if (mat1.columnCount == mat2.rowCount)
			{
				Matrix matrix = new Matrix(mat1.rowCount, mat2.columnCount);
				for (int i = 0; i < matrix.rowCount; i++)
				{
					for (int j = 0; j < matrix.columnCount; j++)
					{
						matrix[i, j] = Matrix.RowMultiColumn(mat1, i, mat2, j);
					}
				}
				return matrix;
			}
			return new Matrix();
		}

		public static bool TotalChoiceGaussElimination(Matrix mat, ref List<double> result)
		{
			if (mat.rowCount != result.Count)
			{
				return false;
			}
			int num = -1;
			int num2 = mat.columnCount;
			List<double> list = new List<double>(num2);
			double num3;
			for (int i = 0; i < num2 - 1; i++)
			{
				num3 = 0.0;
				for (int j = i; j < num2; j++)
				{
					for (int k = i; k < num2; k++)
					{
						double num4 = Math.Abs(mat[j, k]);
						if (num4 > num3)
						{
							num3 = num4;
							list.Insert(i, (double)k);
							num = j;
						}
					}
				}
				if (num3 == 0.0)
				{
					return false;
				}
				if ((int)list[i] != i)
				{
					for (int j = 0; j < num2; j++)
					{
						double num4 = mat[j, i];
						mat[j, i] = mat[j, (int)list[i]];
						mat[j, (int)list[i]] = num4;
					}
				}
				if (num != i)
				{
					double num4;
					for (int k = i; k < num2; k++)
					{
						num4 = mat[i, k];
						mat[i, k] = mat[num, k];
						mat[num, k] = num4;
					}
					num4 = result[i];
					result[i] = result[num];
					result[num] = num4;
				}
				num3 = Math.Abs(mat[i, i]);
				for (int k = i + 1; k < num2; k++)
				{
					int i2 = i;
					int j2 = k;
					mat[i2, j2] /= mat[i, i];
				}
				result[i] /= mat[i, i];
				for (int j = i + 1; j < num2; j++)
				{
					for (int k = i + 1; k < num2; k++)
					{
						mat[j, k] -= mat[j, i] * mat[i, k];
					}
					result[j] -= mat[j, i] * result[i];
				}
			}
			result[num2 - 1] = result[num2 - 1] / mat[num2 - 1, num2 - 1];
			num3 = Math.Abs(mat[num2 - 1, num2 - 1]);
			if (num3 == 0.0)
			{
				return false;
			}
			for (int j = num2 - 2; j >= 0; j--)
			{
				double num5 = 0.0;
				for (int k = j + 1; k < num2; k++)
				{
					num5 += mat[j, k] * result[k];
				}
				result[j] -= num5;
			}
			list[num2 - 1] = (double)(num2 - 1);
			for (int i = num2 - 2; i >= 0; i--)
			{
				if ((int)list[i] != i)
				{
					double num4 = result[i];
					result[i] = result[(int)list[i]];
					result[(int)list[i]] = num4;
				}
			}
			return true;
		}

		private double[,] Values;

		private int rowCount;

		private int columnCount;
	}
}
